#!/usr/bin/env python3
"""
自动清理管理器
磁盘空间不足时自动执行清理操作
"""

import os
import time
import threading
import shutil
from typing import Dict, Any, Optional, List, Callable
from dataclasses import dataclass
from enum import Enum
from .disk_monitor import DiskMonitor, StorageLevel
from .storage_adjuster import StorageAdjuster

class CleanupLevel(Enum):
    """清理级别"""
    NONE = "none"           # 无需清理
    LIGHT = "light"         # 轻度清理
    MODERATE = "moderate"   # 中度清理
    AGGRESSIVE = "aggressive"  # 激进清理
    EMERGENCY = "emergency" # 紧急清理

@dataclass
class CleanupResult:
    """清理结果"""
    level: CleanupLevel
    freed_space: int
    cleaned_files: int
    cleaned_tables: int
    duration: float
    success: bool
    message: str

class AutoCleanupManager:
    """自动清理管理器"""
    
    def __init__(self, data_directory: str = "data"):
        """初始化自动清理管理器"""
        self.data_directory = data_directory
        self.disk_monitor = DiskMonitor(data_directory)
        self.storage_adjuster = StorageAdjuster(data_directory)
        
        # 清理配置
        self.cleanup_config = {
            'enabled': True,
            'check_interval': 60,  # 检查间隔(秒)
            'cleanup_thresholds': {
                StorageLevel.CRITICAL: CleanupLevel.EMERGENCY,
                StorageLevel.LOW: CleanupLevel.AGGRESSIVE,
                StorageLevel.NORMAL: CleanupLevel.LIGHT,
                StorageLevel.HIGH: CleanupLevel.NONE,
                StorageLevel.EXCESS: CleanupLevel.NONE
            },
            'file_retention_days': 30,  # 文件保留天数
            'log_retention_days': 7,    # 日志保留天数
            'temp_file_extensions': ['.tmp', '.temp', '.log', '.bak', '.old'],
            'max_cleanup_duration': 300  # 最大清理时间(秒)
        }
        
        # 清理策略
        self.cleanup_strategies = {
            CleanupLevel.LIGHT: {
                'clean_temp_files': True,
                'clean_old_logs': True,
                'compress_data': False,
                'delete_old_backups': False,
                'vacuum_tables': False
            },
            CleanupLevel.MODERATE: {
                'clean_temp_files': True,
                'clean_old_logs': True,
                'compress_data': True,
                'delete_old_backups': True,
                'vacuum_tables': True
            },
            CleanupLevel.AGGRESSIVE: {
                'clean_temp_files': True,
                'clean_old_logs': True,
                'compress_data': True,
                'delete_old_backups': True,
                'vacuum_tables': True,
                'defragment_tables': True,
                'delete_unused_indexes': True
            },
            CleanupLevel.EMERGENCY: {
                'clean_temp_files': True,
                'clean_old_logs': True,
                'compress_data': True,
                'delete_old_backups': True,
                'vacuum_tables': True,
                'defragment_tables': True,
                'delete_unused_indexes': True,
                'delete_old_data': True,
                'force_cleanup': True
            }
        }
        
        # 统计信息
        self.stats = {
            'total_cleanups': 0,
            'total_freed_space': 0,
            'total_cleaned_files': 0,
            'last_cleanup_time': 0,
            'cleanup_history': []
        }
        
        # 回调函数
        self.cleanup_callbacks: Dict[str, Callable] = {}
        
        # 线程控制
        self.monitoring_thread: Optional[threading.Thread] = None
        self.monitoring_active = False
        self.lock = threading.RLock()
        
        # 注册存储调整器回调
        self.storage_adjuster.register_callback('auto_cleanup', self._on_auto_cleanup_request)
    
    def register_callback(self, event: str, callback: Callable):
        """注册清理回调函数"""
        self.cleanup_callbacks[event] = callback
    
    def _trigger_callback(self, event: str, data: Any = None):
        """触发回调函数"""
        if event in self.cleanup_callbacks:
            try:
                self.cleanup_callbacks[event](data)
            except Exception as e:
                print(f"清理回调函数执行失败: {e}")
    
    def _on_auto_cleanup_request(self, data: Dict):
        """自动清理请求回调"""
        print("收到自动清理请求")
        self.perform_cleanup()
    
    def start_monitoring(self):
        """开始监控"""
        if self.monitoring_active:
            return
        
        self.monitoring_active = True
        self.monitoring_thread = threading.Thread(
            target=self._monitoring_loop,
            daemon=True
        )
        self.monitoring_thread.start()
        print(f"自动清理监控已启动，检查间隔: {self.cleanup_config['check_interval']}秒")
    
    def stop_monitoring(self):
        """停止监控"""
        self.monitoring_active = False
        if self.monitoring_thread:
            self.monitoring_thread.join(timeout=5)
        print("自动清理监控已停止")
    
    def _monitoring_loop(self):
        """监控循环"""
        while self.monitoring_active:
            try:
                # 检查磁盘空间
                disk_info = self.disk_monitor.get_disk_info()
                storage_level = disk_info.level
                
                # 确定清理级别
                cleanup_level = self.cleanup_config['cleanup_thresholds'].get(
                    storage_level, CleanupLevel.NONE
                )
                
                # 如果需要清理，执行清理
                if cleanup_level != CleanupLevel.NONE and self.cleanup_config['enabled']:
                    print(f"磁盘空间不足 ({storage_level.value})，执行 {cleanup_level.value} 级别清理")
                    self.perform_cleanup(cleanup_level)
                
                # 等待下次检查
                time.sleep(self.cleanup_config['check_interval'])
                
            except Exception as e:
                print(f"自动清理监控错误: {e}")
                time.sleep(self.cleanup_config['check_interval'])
    
    def perform_cleanup(self, level: CleanupLevel = None) -> CleanupResult:
        """执行清理操作"""
        start_time = time.time()
        
        with self.lock:
            # 确定清理级别
            if level is None:
                disk_info = self.disk_monitor.get_disk_info()
                level = self.cleanup_config['cleanup_thresholds'].get(
                    disk_info.level, CleanupLevel.LIGHT
                )
            
            print(f"开始执行 {level.value} 级别清理...")
            
            # 获取清理前的磁盘信息
            disk_info_before = self.disk_monitor.get_disk_info()
            
            # 执行清理策略
            strategy = self.cleanup_strategies.get(level, {})
            total_freed_space = 0
            total_cleaned_files = 0
            cleaned_tables = 0
            
            try:
                # 清理临时文件
                if strategy.get('clean_temp_files', False):
                    freed, files = self._clean_temp_files()
                    total_freed_space += freed
                    total_cleaned_files += files
                
                # 清理旧日志
                if strategy.get('clean_old_logs', False):
                    freed, files = self._clean_old_logs()
                    total_freed_space += freed
                    total_cleaned_files += files
                
                # 压缩数据
                if strategy.get('compress_data', False):
                    freed = self._compress_data()
                    total_freed_space += freed
                
                # 删除旧备份
                if strategy.get('delete_old_backups', False):
                    freed, files = self._delete_old_backups()
                    total_freed_space += freed
                    total_cleaned_files += files
                
                # 清理表
                if strategy.get('vacuum_tables', False):
                    tables = self._vacuum_tables()
                    cleaned_tables = len(tables)
                
                # 碎片整理
                if strategy.get('defragment_tables', False):
                    self._defragment_tables()
                
                # 删除未使用的索引
                if strategy.get('delete_unused_indexes', False):
                    self._delete_unused_indexes()
                
                # 删除旧数据
                if strategy.get('delete_old_data', False):
                    freed, files = self._delete_old_data()
                    total_freed_space += freed
                    total_cleaned_files += files
                
                # 强制清理
                if strategy.get('force_cleanup', False):
                    freed, files = self._force_cleanup()
                    total_freed_space += freed
                    total_cleaned_files += files
                
                # 计算清理时间
                duration = time.time() - start_time
                
                # 更新统计信息
                self.stats['total_cleanups'] += 1
                self.stats['total_freed_space'] += total_freed_space
                self.stats['total_cleaned_files'] += total_cleaned_files
                self.stats['last_cleanup_time'] = time.time()
                
                # 记录清理历史
                cleanup_record = {
                    'timestamp': time.time(),
                    'level': level.value,
                    'freed_space': total_freed_space,
                    'cleaned_files': total_cleaned_files,
                    'cleaned_tables': cleaned_tables,
                    'duration': duration
                }
                self.stats['cleanup_history'].append(cleanup_record)
                
                # 保持历史记录不超过100条
                if len(self.stats['cleanup_history']) > 100:
                    self.stats['cleanup_history'].pop(0)
                
                # 创建清理结果
                result = CleanupResult(
                    level=level,
                    freed_space=total_freed_space,
                    cleaned_files=total_cleaned_files,
                    cleaned_tables=cleaned_tables,
                    duration=duration,
                    success=True,
                    message=f"成功执行 {level.value} 级别清理"
                )
                
                # 触发清理完成回调
                self._trigger_callback('cleanup_completed', result)
                
                print(f"清理完成: 释放空间 {self.disk_monitor.format_size(total_freed_space)}, "
                      f"清理文件 {total_cleaned_files}, 清理表 {cleaned_tables}, "
                      f"耗时 {duration:.2f}秒")
                
                return result
                
            except Exception as e:
                duration = time.time() - start_time
                error_msg = f"清理失败: {str(e)}"
                print(error_msg)
                
                result = CleanupResult(
                    level=level,
                    freed_space=0,
                    cleaned_files=0,
                    cleaned_tables=0,
                    duration=duration,
                    success=False,
                    message=error_msg
                )
                
                # 触发清理失败回调
                self._trigger_callback('cleanup_failed', result)
                
                return result
    
    def _clean_temp_files(self) -> tuple[int, int]:
        """清理临时文件"""
        print("清理临时文件...")
        freed_space = 0
        cleaned_files = 0
        
        temp_extensions = self.cleanup_config['temp_file_extensions']
        
        if os.path.exists(self.data_directory):
            for dirpath, dirnames, filenames in os.walk(self.data_directory):
                for filename in filenames:
                    if any(filename.endswith(ext) for ext in temp_extensions):
                        filepath = os.path.join(dirpath, filename)
                        try:
                            file_size = os.path.getsize(filepath)
                            os.remove(filepath)
                            freed_space += file_size
                            cleaned_files += 1
                        except OSError:
                            continue
        
        print(f"清理了 {cleaned_files} 个临时文件，释放空间 {self.disk_monitor.format_size(freed_space)}")
        return freed_space, cleaned_files
    
    def _clean_old_logs(self) -> tuple[int, int]:
        """清理旧日志"""
        print("清理旧日志...")
        freed_space = 0
        cleaned_files = 0
        
        cutoff_time = time.time() - (self.cleanup_config['log_retention_days'] * 24 * 3600)
        
        if os.path.exists(self.data_directory):
            for dirpath, dirnames, filenames in os.walk(self.data_directory):
                for filename in filenames:
                    if filename.endswith('.log'):
                        filepath = os.path.join(dirpath, filename)
                        try:
                            file_mtime = os.path.getmtime(filepath)
                            if file_mtime < cutoff_time:
                                file_size = os.path.getsize(filepath)
                                os.remove(filepath)
                                freed_space += file_size
                                cleaned_files += 1
                        except OSError:
                            continue
        
        print(f"清理了 {cleaned_files} 个旧日志文件，释放空间 {self.disk_monitor.format_size(freed_space)}")
        return freed_space, cleaned_files
    
    def _compress_data(self) -> int:
        """压缩数据"""
        print("压缩数据文件...")
        # 这里可以实现数据压缩逻辑
        # 暂时返回0
        return 0
    
    def _delete_old_backups(self) -> tuple[int, int]:
        """删除旧备份"""
        print("删除旧备份...")
        freed_space = 0
        cleaned_files = 0
        
        cutoff_time = time.time() - (self.cleanup_config['file_retention_days'] * 24 * 3600)
        
        if os.path.exists(self.data_directory):
            for dirpath, dirnames, filenames in os.walk(self.data_directory):
                for filename in filenames:
                    if filename.endswith('.bak') or 'backup' in filename.lower():
                        filepath = os.path.join(dirpath, filename)
                        try:
                            file_mtime = os.path.getmtime(filepath)
                            if file_mtime < cutoff_time:
                                file_size = os.path.getsize(filepath)
                                os.remove(filepath)
                                freed_space += file_size
                                cleaned_files += 1
                        except OSError:
                            continue
        
        print(f"删除了 {cleaned_files} 个旧备份文件，释放空间 {self.disk_monitor.format_size(freed_space)}")
        return freed_space, cleaned_files
    
    def _vacuum_tables(self) -> List[str]:
        """清理表"""
        print("清理表...")
        # 这里可以实现表清理逻辑
        # 暂时返回空列表
        return []
    
    def _defragment_tables(self):
        """碎片整理表"""
        print("执行表碎片整理...")
        # 这里可以实现表碎片整理逻辑
    
    def _delete_unused_indexes(self):
        """删除未使用的索引"""
        print("删除未使用的索引...")
        # 这里可以实现索引清理逻辑
    
    def _delete_old_data(self) -> tuple[int, int]:
        """删除旧数据"""
        print("删除旧数据...")
        # 这里可以实现旧数据删除逻辑
        # 暂时返回0
        return 0, 0
    
    def _force_cleanup(self) -> tuple[int, int]:
        """强制清理"""
        print("执行强制清理...")
        # 这里可以实现强制清理逻辑
        # 暂时返回0
        return 0, 0
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        with self.lock:
            return {
                'total_cleanups': self.stats['total_cleanups'],
                'total_freed_space': self.stats['total_freed_space'],
                'total_cleaned_files': self.stats['total_cleaned_files'],
                'last_cleanup_time': self.stats['last_cleanup_time'],
                'cleanup_history': self.stats['cleanup_history'][-10:],  # 最近10次清理记录
                'monitoring_active': self.monitoring_active,
                'cleanup_enabled': self.cleanup_config['enabled']
            }
    
    def print_status(self):
        """打印状态"""
        stats = self.get_stats()
        
        print("=" * 60)
        print("自动清理状态")
        print("=" * 60)
        print(f"监控状态: {'活跃' if stats['monitoring_active'] else '停止'}")
        print(f"清理启用: {'是' if stats['cleanup_enabled'] else '否'}")
        print(f"总清理次数: {stats['total_cleanups']}")
        print(f"总释放空间: {self.disk_monitor.format_size(stats['total_freed_space'])}")
        print(f"总清理文件: {stats['total_cleaned_files']}")
        print(f"最后清理时间: {time.ctime(stats['last_cleanup_time']) if stats['last_cleanup_time'] > 0 else '从未'}")
        print()
        
        # 清理历史
        if stats['cleanup_history']:
            print("最近清理记录:")
            for record in stats['cleanup_history']:
                print(f"  {time.ctime(record['timestamp'])}: {record['level']} 级别, "
                      f"释放 {self.disk_monitor.format_size(record['freed_space'])}, "
                      f"清理 {record['cleaned_files']} 个文件, "
                      f"耗时 {record['duration']:.2f}秒")
    
    def set_cleanup_config(self, config: Dict[str, Any]):
        """设置清理配置"""
        with self.lock:
            self.cleanup_config.update(config)
            print("清理配置已更新")
    
    def enable_cleanup(self):
        """启用清理"""
        self.cleanup_config['enabled'] = True
        print("自动清理已启用")
    
    def disable_cleanup(self):
        """禁用清理"""
        self.cleanup_config['enabled'] = False
        print("自动清理已禁用")
    
    def shutdown(self):
        """关闭自动清理管理器"""
        print("关闭自动清理管理器...")
        
        # 停止监控
        self.stop_monitoring()
        
        # 停止存储调整器
        self.storage_adjuster.stop_monitoring()
        
        print("自动清理管理器已关闭")